﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net;
using System.Net.Sockets;

namespace AuktionsServer
{
    class KlientHandler
    {
        private Socket klientSocket;
        private NetworkStream netStream;
        private StreamWriter writer;
        private StreamReader reader;


        private Services services;  // associering med services klassen
        private Klient aktuelKlient; //aktuelKlient holder den aktuelle klient, som logge på. 
        private int tal; //tal holder information om den aktuelle bud
        private string input; // input holder information om svaret fra klienten
        private object _lås = new object(); // tråd sikring
        private string klientIp; //holder klientens ip adresse i string format


        /// <summary>
        /// bruges til at undersøge, hvis klientens besked skal broadcastes eller ej
        /// </summary>
		private bool login; 
        private bool stop;


        /// <summary>
        /// Konstruktoren bruges til associering med Services klassen. Samtidigt henter den aktuelle klientens forbindelse 
        /// fra Server klassen. 
        /// </summary>
        /// <param name="klientSocket"></param> klientSocket hentes fra serveren
        /// <param name="services"></param> services hentes fra serveren - associering med services klassen
        public KlientHandler(Socket klientSocket, Services services)
        {
            this.klientSocket = klientSocket;
            this.services = services;
            klientIp = klientSocket.RemoteEndPoint.ToString();
        }

        /// <summary>
        /// KoerKlient metoden bruges i tråden på serveren. 
        /// Metoden opretter den nødvendige funktioner til komunikationen med klienten. (networkStream, streamWriter og streamReader)
        /// DoDialog metoden styrer komunikation mellem server og klient.
        /// Når dialogen er afsluttet, KoerKlient metoden slukker for forbindelsen mellem klient og server.
        /// </summary>
        public void KoerKlient()
        {
            this.netStream = new NetworkStream(klientSocket);
            this.writer = new StreamWriter(netStream);
            this.reader = new StreamReader(netStream);

            DoDialog();

            this.writer.Close();
            this.reader.Close();
            this.netStream.Close();
            this.klientSocket.Shutdown(SocketShutdown.Both);
            this.klientSocket.Close();
        }
        
        private void SendTilKlient(string tekst) // en lille metode sender beskeden gennem networkStream
        {
            writer.WriteLine(tekst);
            writer.Flush();
        }

        private string ModtagFraKlient() // en lille metode læser besked fra networkStream
        {
            try
            {
                return reader.ReadLine();
            }
            catch
            {
                return null;
            }
        }

        private void DoDialog()
        {
            try
            {
				services.BroadcastEvent += this.BroadcastAction; // BroadcastAction tilføjes til BroadcastEvent i services klasse
				while (ExecuteCommand()) // denne while løkke sørger for at ExecuteCommand kører indtil den returnere false 
                { }
            }
            catch
            { }
            finally
            {
                services.BroadcastEvent -= this.BroadcastAction; //BroadcastAction fjernes fra BroadcastEvent i services klasse
                try
                {
                    Server.Klienter.Remove(this.aktuelKlient); //aktuelKlient fjernes fra klient listen
                }
                catch { } // ikke implementeret
            }
        }

        private void OpretKlient(string navn, string ip) // metoden bruges til at oprette en klient
        {
            this.aktuelKlient = new Klient(navn, ip);
            Server.Klienter.Add(aktuelKlient);  // klienten tilføjes til listen over klienter
        }

        private bool ValiderKlient(string navn) //metoden kaldes, når en klient skal tjekkes, (tjekker hvis klienten er på klientliste med dens navn
        {
            foreach (Klient klient in Server.Klienter) //tjekker hver klient, indtil klienten findes (returnere true)
            {
                if (klient.Navn == navn)
                {
                    return true;
                }
                else
                    return false;
            }
            return false;
        }

        private bool ExecuteCommand() // behandler de sendte og modtagende beskeder fra/til klienten
        {
            try
            {
                input = ModtagFraKlient();  

                if (!Int32.TryParse(input, out tal)) //her undersøges, hvis svaret fra klienten er et tal eller en string
                {
                    string navn = input;
					lock (_lås) //object lås, sørger for at kun en klient bruger listen ad gangen.
					{
						if (Server.Klienter.Count != 0) //tjekker, hvis der er klient på klientlisten
						{
							bool navnfindes = false;
							
                            if (ValiderKlient(navn)) 
							{
	                            navnfindes = true; // hvis klienten findes returnere true
							}	
							if (!navnfindes)    //hvis klienten ikke findes på listen, klienten bliver oprettet her
							{
								OpretKlient(navn, this.klientIp);
								input = "sandt";    //sender svar til klient brugergranseflæde, som behandles derover
								SendTilKlient(input);
								Console.WriteLine("Klient Ankommet: "+navn+"("+klientIp+")");
								SendTilKlient(services.AuktionsInformation(0));
								login = true;   //klienten er logget på 
							}
							else
							{
								input = "falsk";    // sender beskeden til klient brugergranseflæde, som behandles derover
								SendTilKlient(input);
							}
						}
						else //hvis klientlisten er tom, klienten tilføjes uden validering.
						{
							OpretKlient(navn, this.klientIp);
							input = "sandt";
							SendTilKlient(input);
							Console.WriteLine("Klient Ankommet: " + navn + "(" + klientIp + ")");
							SendTilKlient(services.AuktionsInformation(0));
							login = true;
						}
					}
                    return true; //sørger for at executeCommand kører igen 
                }
                else
                {
                    input = services.ModtagBud(tal, this.aktuelKlient.ID); //hvis svaret er et tal, så bliver tallet til en bud.

					if (input == "underbud" || input == "mindstebud" || input == "lukket")
                    {
						SendTilKlient(input);
						return true;
                    }
					else
                    {
                        services.BroadcastBesked(aktuelKlient.Navn + " byder: " + input);
                        return true;
                    }
                }
            }
            catch
            {
                return false;
            }
        }

		public void BroadcastAction(string besked)
		{
			if (login)//Sørger for at der kun bliver broadcastet til brugeren hvis brugeren er logget ind
			{
				if (besked.Contains("Solgt"))//Ved "Solgt" når auktionen afsluttes
				{
					string[] inputarr = besked.Split('%');//Strengen hedder "Solgt til %" + auktion.VinderID + "% for " + auktion.Bud + " kr"
					foreach (Klient klient in Server.Klienter)
					{
						if (klient.ID.ToString() == inputarr[1])//inputarr[1] er vinderIDet
						{
							besked = inputarr[0] + klient.Navn + "("+klient.Ip+")"+ inputarr[2];
						}
					}
				}
				SendTilKlient(besked);
			}
		}
    }
}


